#import "PrefsManager.h"
#import "NuString.h"
#import <appkit/appkit.h>
#import <defaults/defaults.h>
#import <objc/List.h>
#import <strings.h>
#import <ctype.h>
#import "MenuManager.h"

// set to YES iff we are setting the NuPath
// var via a modal loop
BOOL modalSetup = NO ;

// defaults to use if none in database
static NXDefaultsVector nuDefaults = 
{ {"NuPath",""},
  {"NXFont","Ohlfs"},
  {"NXFontSize","11.0"},
  {"HeightInChars","25"},
  {"WidthInChars","25"},
  {"Flags","101"},
  {"CompilerOptions","-w -g"},
  {"Libraries","/usr/local/lib/libmusickit.a /usr/local/lib/libsynthpatches.a "
     "/usr/local/lib/libunitgenerators.a /usr/local/lib/libdsp.a "
     "/usr/lib/libNeXT_p.a"},
  // importText,atText,methodText,commentText,otherText
  {"classText0",  "Courier \\fs28  \\red0\\green0\\blue0 \\b0 \\i0 \\ul0"},
  {"classText1",  "Courier \\fs28 \\red0\\green0\\blue0  \\b0 \\i0 \\ul0"},
  {"classText2",  "Ohlfs \\fs22 \\red0\\green0\\blue0  \\b \\i \\ul"},
  {"classText3",  "Courier \\fs22 \\red0\\green0\\blue0  \\b0 \\i0 \\ul0"},
  {"classText4",  "Courier \\fs22 \\red0\\green0\\blue0  \\b0 \\i1 \\ul0 "},
  {NULL} 
} ;

// archive (library) extension 
const char *libTypes[] = 
{ "a",
  NULL 
} ;


@implementation PrefsManager: Object
{  id // the preferences view
     prefView,
     // default path
     NuPath,
     // default font and size
     NXFont, NXFontSize,
     // classmanager and workspace behavior
     manyOne, backupRTF, 
     // classmanager formatting:
     // importText, atText, methodText,
     // commentText, otherText     
     classText0, classText1,
     classText2, classText3, classText4,
     // compile and link parameters
     compilerOptions, linkBrowser,
     linkList, debugFile,
    // need to change behavior of class text scroll object
     classTextScroller ;
}
- (int)browser:sender fillMatrix:matrix inColumn:(int)column ;
{ // delegate method for browser object 
  return [linkList count] ;
}

- browser:sender loadCell:cell atRow:(int)row inColumn:(int)column ;
{ [cell setStringValue: [[linkList objectAt: row] cString]] ;
  [cell setLeaf: YES] ;
  return self ;
}

- changePref: sender ;
{ // move the prefView to the "correct" location.
  // prefView panels are 400 points wide.
  [prefView moveTo:[[sender selectedCell] tag] * -400.0 :0.0] ;
  [[prefView window] display] ;
  return self ;
}



- linkAdd: sender ;
{ // add a library file's name to the list
  // of libraries to be searched
  id openPanel ;
  char **theList, buf[256] ;

  openPanel = [OpenPanel new] ;
  if([openPanel runModalForTypes: libTypes])
  { theList = (char **) [openPanel filenames] ;
    { sprintf(buf,"%s/%s",[openPanel directory],
        *theList++) ;
      [linkList addObject: [NuString new:buf]] ;
    }
    [linkBrowser loadColumnZero] ;
    [self setDefaults: self] ;
  }  
  return self ;   
}

- linkList ;
{ return linkList ;
}

- linkRemove: sender ;
{ // remove a library file's name to the list
  // of libraries to be searched
  int theRow ;
  theRow = [[linkBrowser matrixInColumn: 0] selectedRow] ;
  if(theRow >= 0)
  { [[linkList removeObjectAt: theRow] free] ;
    [linkBrowser loadColumnZero] ;
    [self setDefaults: self] ;
  }
  return self ;
}

- setDefaults: sender ;
{ // write info from defaults panel to defaults
  // database and to objects as needed
  char flags[10], ivar[12], theText[5][256], libString[2048] ;
  id theIvar ;
  int i, knt ;
  NXColor aColor ;
  float red,green,blue ;
  NXDefaultsVector theDefaults =
  { {"NuPath",NULL},
    {"NXFont",NULL},
    {"NXFontSize",NULL},
    {"Flags",NULL} ,
    {"Libraries",NULL},
    {"CompilerOptions",NULL},
    {"classText0",NULL},
    {"classText1", NULL},
    {"classText2",NULL},
    {"classText3",NULL},
    {"classText4",NULL},
    {NULL}
  } ;
  // if we are setting the NuPath for the first time, then
  // we are running modally, and must abort the modal loop
  if(modalSetup && ([sender cell] == NuPath))
  { [NXApp stopModal] ;
    [[prefView window] orderOut: self] ;
  }
  // fetch the current values
  theDefaults[0].value = (char *) [NuPath stringValue] ;
  theDefaults[1].value = (char *) [NXFont stringValue] ;
  theDefaults[2].value = (char *) [NXFontSize stringValue] ;
  // set flag values
  flags[BACKUPRTF] = (char) [backupRTF selectedCol] + '0' ;
  flags[DEBUGFILES] = (char) [debugFile selectedCol] + '0' ;
  flags[MULTIPLECLASSWINDOWS] = (char) [manyOne selectedCol] + '0' ;
  flags[3] = '\0' ;
  theDefaults[3].value = flags ;
  // set the Libraries preference
  knt = [linkList count] ;
  libString[0] = '\0' ;
  for(i = 0 ; i < knt ; i++)
  { strcat(libString,[[linkList objectAt: i] cString]) ;
    strcat(libString," ") ;
  }
  theDefaults[4].value = libString ;
  // set the compiler options
  theDefaults[5].value = (char *) [compilerOptions stringValue] ;
  // set the classText prefs
  for(i = 0 ; i < 5 ; i++)
  { // "manufacture" the instance vars classText0, classText1, ...
    sprintf(ivar,"classText%1d",i) ;
    object_getInstanceVariable(self,ivar,(void **) &theIvar) ;
    // grab the color...
    aColor = [[theIvar findViewWithTag: 2] color] ;
    NXConvertColorToRGBA (aColor, &red, &green, &blue, NULL);
    sprintf(theText[i],"%s \\fs%d \\red%d\\green%d\\blue%d \\b%s \\i%s \\ul%s", 
      [[theIvar findViewWithTag: 0] stringValue] ,
      (int) ([[theIvar findViewWithTag: 1] floatValue] * 2),
      (int)(red * 256), (int) (green * 256), (int) (blue * 256),
      [[theIvar findViewWithTag: 3] state] ? "" : "0",
      [[theIvar findViewWithTag: 4] state] ? "" : "0",
      [[theIvar findViewWithTag: 5] state] ? "" : "0") ;
[Nu printf: "theText[%d] = %s\n",i,theText[i]] ;
    theDefaults[i + 6].value = (char *) theText[i] ;
  }
  NXWriteDefaults([NXApp appName], theDefaults) ; 
  return self ;
}

- setClassTextScroller: anObject ;
{ // need to change behavior of scroller to
  // workaround appkit bug with scrollers
  classTextScroller = anObject ;
  [anObject setCopyOnScroll: NO] ;
  [anObject setDynamicScrolling: NO] ;
  return self ;
}

- setup ;
{ // perform initialization
  const char *appName, *flags, *defaults ;
  char ivar[12],fontName[12],fontBold[12], 
       fontItalic[12], fontUnderline[12] ;
  int i, fontSize, red, green, blue ;
  id theIvar ;
    
  appName = [NXApp appName] ;
  NXRegisterDefaults([NXApp appName], nuDefaults) ;
  [NXFont setStringValue: NXGetDefaultValue(appName,"NXFont")] ;
  [NXFontSize setStringValue: NXGetDefaultValue(appName,"NXFontSize")] ;
  [NuPath setStringValue: NXGetDefaultValue(appName,"NuPath")] ;
  flags = NXGetDefaultValue(appName,"Flags") ;
  [backupRTF selectCellAt: 0 :flags[BACKUPRTF] - '0'] ;
  [debugFile selectCellAt: 0 :flags[DEBUGFILES] - '0'] ; 
  [manyOne selectCellAt: 0 :flags[MULTIPLECLASSWINDOWS] - '0'] ; 
  for(i = 0 ; i < 5 ; i++)
  { // "manufacture" the dread, ivar names classText0, classText1, ...    
    sprintf(ivar,"classText%1d",i) ;
    object_getInstanceVariable(self,ivar,(void **) &theIvar) ;
    defaults = NXGetDefaultValue(appName,ivar) ;
    sscanf(defaults,"%s \\fs%d \\red%d\\green%d\\blue%d %s %s %s ",
       fontName, &fontSize, &red, &green, &blue, fontBold, fontItalic, fontUnderline) ;
    [[theIvar findViewWithTag: 0] setStringValue: fontName] ;
    [[theIvar findViewWithTag: 1] setIntValue: fontSize / 2.0] ;
    [[theIvar findViewWithTag: 2] setColor:
      NXConvertRGBAToColor(red * 256.0, green * 256.0 , 
       blue * 256.0, NX_NOALPHA)];
    [[theIvar findViewWithTag: 3] setState: !strcmp(fontBold,"\\b") ? 1 : 0] ;
    [[theIvar findViewWithTag: 4] setState: !strcmp(fontItalic,"\\i") ? 1 : 0] ;
    [[theIvar findViewWithTag: 5] setState: !strcmp(fontUnderline,"\\ul") ? 1 : 0] ;
  }

  // init the linkList
  { char libPath[512] ;
    const char *libraries ;
    int i = 0, rval ;
    linkList = [[List alloc] init] ;
    libraries = NXGetDefaultValue(appName,"Libraries") ;
    rval = sscanf(libraries,"%s",libPath) ;
    while(rval == 1)
    { [linkList addObject: [NuString new: libPath]] ;
      while(libraries[i] &&
        !isspace(libraries[i++])) ; // find next library
      rval = sscanf(&libraries[i],"%s",libPath) ;
    }
    [linkBrowser loadColumnZero] ;
  }  
  // init the compiler options
  [compilerOptions setStringValue: 
         NXGetDefaultValue(appName,"CompilerOptions")] ;
  // download postscript to server
  return self ;
}

- setNuPath ;
{ // the first time a user runs Nu, the NuPath pref will not
  // be set, so this code will be invoked to force them to set it
  int rval = NXRunAlertPanel("Nu",
    "The Glyph Path is incorrect or has never been set.\n"
      "Please use the preferences panel to set it now.",
    "Set","Quit Without Setting",NULL) ;
  if(rval == NX_ALERTALTERNATE)
       [NXApp terminate: self] ;
  modalSetup = YES ;
  [NXApp runModalFor: [prefView window]] ;
  modalSetup = NO ;
  return self ;
}

@end